﻿/**
 * @brief 用于多线程tcp client的私有实现
 * @author Zr
 * @date 20230221
 */
#pragma once

#include <QHostAddress>
#include <QMutex>
#include <QTcpSocket>
#include <QThreadPool>
#include <QWaitCondition>
#include <atomic>

namespace ZTcp {
/**
 * @brief 用于多线程tcp client的私有实现
 */
class TcpClient_T_Private : public QObject {
  Q_OBJECT
 public:
  /**
   * @brief 构造函数
   * @param socketDescriptor server接收到的socket handle,默认-1时自动建立
   * @param useTaskPool 是否使用多线程线程池,false时线程池只用1个线程,保证顺序执行任务
   */
  explicit TcpClient_T_Private(qintptr socketDescriptor = -1, bool useTaskPool = true, QWaitCondition* waitDataTrans = nullptr, QObject* parent = nullptr);

  ~TcpClient_T_Private() override;

  /**
   * @brief 指定socket自身的ip port,Client端必须在线程启动前进行执行
   * @param address socket自身的ip
   * @param port socket自身的port
   * @return
   */
  void bind(const QHostAddress& address, quint16 port = 0);

  /**
   * @brief 连接到指定的server,Client端必须在线程启动前进行执行
   * @param address server的ip
   * @param port server的port
   */
  void connectToHost(const QHostAddress& address, quint16 port);

  /**
   * @brief 当接收到一帧信息时进行处理
   * @param f 回调处理函数
   */
  void readCall(std::function<void(const QByteArray&)> f);

  /**
   * @brief 是否已经连接
   * @return true表示已经连接
   */
  bool isConnected();

  /**
   * @brief 返回socket自身绑定的ip
   * @return socket自身绑定的ip
   */
  const QHostAddress& localAddress() const;

  /**
   * @brief 返回socket自身绑定的port
   * @return socket自身绑定的port
   */
  quint16 localPort() const;

  /**
   * @brief 返回socket对端的ip
   * @return socket对端ip
   */
  QHostAddress peerAddress() const;

  /**
   * @brief 返回socket对端的port
   * @return socket对端的port
   */
  quint16 peerPort() const;

  /**
   * @brief 是否当前的tcp处于繁忙状态
   * @return true表示繁忙
   */
  bool isBusy();

  /**
   * @brief 设置当前的tcp繁忙状态
   * @return true表示繁忙
   */
  void setIsBusy(bool arg);

 public slots:
  /**
   * @brief 初始化自身并启动,需要在线程启动后进行执行
   */
  void slotStart();

  /**
   * @brief 写入消息
   * @param arg 信息
   */
  void slotWrite(const QByteArray& arg);

  /**
   * @brief 写入消息指针+大小,需要调用者保证数据可以安全到达多线程并且等待写入完毕
   * @param ptr 消息指针
   * @param size 消息大小
   */
  void slotWritePtr(char* ptr, int size);

 private slots:
  /**
   * @brief 读取数据并进行处理
   */
  void slotReadMsg();

 private:
  /** @brief true表示处于连接状态 */
  std::atomic_bool isConnected_;

  /** @brief socket的底层描述handle */
  qintptr socketDescriptor_;

  /** @brief socket */
  QTcpSocket* socket_;

  /** @brief 处理消息的回调函数 */
  std::function<void(QByteArray)> f_;

  /** @brief 用于发送的buffer */
  QByteArray sendBuffer_;

  /** @brief socket自身的ip */
  QHostAddress localAddress_;
  /** @brief socket自身的port */
  quint16 localPort_;

  /** @brief server的ip */
  QHostAddress serverAddress_;
  /** @brief server的port */
  quint16 serverPort_;

  /** @brief 任务池,进行任务处理 */
  QThreadPool* taskPool_;

  /** @brief 是否启用任务池多线程进行任务处理,false时pool只开启1个线程 */
  bool useTaskPool_;

  /** @brief true表示处于连接状态 */
  std::atomic_bool isBusy_;

  /** @brief 用于等待数据发送完毕的条件变量 */
  QWaitCondition* waitDataTrans_;

 signals:
  /**
    * @brief 启动完成
    */
  void sigStartDone();

  /**
   * @brief 断开连接时发送信息
   */
  void sigDisconnected();
};
}// namespace ZTcp
